﻿/**
 *       Project: ServerLib
 *     Copyright: Copyright (C) 2008, Rob Kennedy
 *   Create Date: 2008-07-15 3:40 PM
 * Modified Date: 2008-07-15 3:40 PM    RK  Added comments
 *      Comments: Ignore SA1633.
 *      
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

namespace ServerLib.Settings
{
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Data;
    using System.Linq;
    using System.Net.Mail;
    using ServerLib.Data;

    /// --------------------------------------------------------------------
    /// Project	 : ServerLib
    /// Class	 : ServerSettings
    /// Inherits : None.
    /// --------------------------------------------------------------------
    /// <summary>
    /// The main server settings class provides access to the database
    /// object collections and methods to access class objects
    /// </summary>
    /// <authorname>Rob Kennedy</authorname>
    /// <remarks></remarks>
    /// --------------------------------------------------------------------
    public class ServerSettings
    {
        #region Private Properties

        /// <summary>
        /// Contains the database connection object
        /// </summary>
        private IDatabase dataConnection;

        /// <summary>
        /// Contains a collection list of domain records
        /// </summary>
        private Collection<Domain> serverDomains = new Collection<Domain>();
        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the internal database connection object
        /// </summary>
        public IDatabase Connection
        {
            get
            {
                return this.dataConnection;
            }
        }

        /// <summary>
        /// Gets a collection list of domain records
        /// </summary>
        public Collection<Domain> Domains
        {
            get
            {
                if (this.Connection != null)
                {
                    this.serverDomains.Clear();

                    bool wasPreviouslyOpen = this.Connection.IsConnected;

                    if (!wasPreviouslyOpen)
                    {
                        this.Connection.Open();
                    }

                    if (this.Connection.IsConnected)
                    {
                        DataTable resultsTable = this.Connection.SelectQuery(SqlCommandStringBuilder.BuildSelect("Domains", null));

                        if (resultsTable != null)
                        {
                            foreach (DataRow domainRow in resultsTable.Rows)
                            {
                                this.serverDomains.Add(new Domain(domainRow));
                            }
                        }
                    }

                    if (!wasPreviouslyOpen)
                    {
                        this.Connection.Close();
                    }
                }

                return this.serverDomains;
            }
        }
        #endregion

        #region Public Constructors
        
        /// <summary>
        /// Initializes the Server Settings object
        /// </summary>
        /// <param name="dataConnection">database connection object</param>
        public ServerSettings(IDatabase dataConnection)
        {
            this.dataConnection = dataConnection;
        }
        #endregion

        #region Public Methods

        /// <summary>
        /// Find a domain object by ID within the Domains collection list
        /// </summary>
        /// <param name="domainId">The domain Id to search for</param>
        /// <returns>Returns a Domain object if found, otherwise null</returns>
        public Domain FindDomain(int domainId)
        {
            Domain resultValue = null;

            IEnumerable<Domain> results = from dom in this.serverDomains
                                          where dom.DomainID == domainId
                                          select dom;

            if (results != null)
            {
                if (results.Count<Domain>() > 0)
                {
                    resultValue = results.ElementAt<Domain>(0);
                }
            }

            return resultValue;
        }

        /// <summary>
        /// Find a domain object by Name within the Domains collection list
        /// </summary>
        /// <param name="domainName">The domain name to search for</param>
        /// <returns>Returns a Domain object if found, otherwise null</returns>
        public Domain FindDomain(string domainName)
        {
            Domain resultValue = null;

            IEnumerable<Domain> results = from dom in this.serverDomains
                                          where dom.DomainName.ToLower() == domainName.ToLower()
                                          select dom;

            if (results != null)
            {
                if (results.Count<Domain>() > 0)
                {
                    resultValue = results.ElementAt<Domain>(0);
                }
            }

            return resultValue;
        }

        /// <summary>
        /// Find a User object by ID within a User collection list
        /// </summary>
        /// <param name="userId">The User Id to search for</param>
        /// <returns>Returns a User object if found, otherwise null</returns>
        public User FindUser(int userId)
        {
            User resultValue = null;

            foreach (Domain domain in this.serverDomains)
            {
                IEnumerable<User> results = from usr in domain.Users
                                            where usr.UserID == userId
                                            select usr;

                if (results != null ? results.Count<User>() > 0 : false)
                {
                    resultValue = results.ElementAt<User>(0);
                    break;
                }
            }

            return resultValue;
        }

        /// <summary>
        /// Find a User object by email Address within a User collection list
        /// </summary>
        /// <param name="emailAddress">The User email address to search for</param>
        /// <returns>Returns a User object if found, otherwise null</returns>
        public User FindUser(string emailAddress)
        {
            User resultValue = null;
            
            MailAddress address = new MailAddress(emailAddress);
            
            Domain localDomain = this.FindDomain(address.Host);

            if (localDomain != null)
            {
                IEnumerable<User> results = from usr in localDomain.Users
                                            where usr.UserName.ToLower() == address.User.ToLower()
                                            select usr;

                if (results != null ? results.Count<User>() > 0 : false)
                {
                    // found a user account record with this name for this domain
                    resultValue = results.ElementAt<User>(0);
                }
                else if (results == null || (results != null ? results.Count<User>() == 0 : false))
                {
                    // no user accounts matched this so check aliases
                    IEnumerable<Alias> aliases = from alias in localDomain.Aliases
                                                 where alias.AliasName == address.User.ToLower()
                                                 select alias;

                    if (aliases != null ? aliases.Count<Alias>() > 0 : false)
                    {
                        // we found an alias for this address, get account name...
                        Alias aliasFound = aliases.ElementAt<Alias>(0);
                        if (aliasFound != null)
                        {
                            resultValue = this.FindUser(aliasFound.UserID);
                        }
                    }
                }
            }

            return resultValue;
        }

        /// <summary>
        /// Find a collection of users for a specific alias email address
        /// </summary>
        /// <param name="aliasAddress">Alias e-mail address to search for</param>
        /// <returns>Returns a collection list of users for a specified e-mail alias</returns>
        public Collection<User> FindUsers(string aliasAddress)
        {
            Collection<User> resultValue = new Collection<User>();

            MailAddress address = new MailAddress(aliasAddress);
            
            Domain localDomain = this.FindDomain(address.Host);

            if (localDomain != null)
            {
                // no user accounts matched this so check aliases
                IEnumerable<Alias> aliases = from alias in localDomain.Aliases
                                             where alias.AliasName == address.User.ToLower()
                                             select alias;

                if (aliases != null ? aliases.Count<Alias>() > 0 : false)
                {
                    // we found an alias for this address, get account name...
                    Alias aliasFound = aliases.ElementAt<Alias>(0);
                    if (aliasFound != null)
                    {
                        resultValue = aliasFound.AdditionalUsers;
                    }
                }
            }

            return resultValue;
        }

        /// <summary>
        /// Find a collection of mailing list e-mail addresses for a specific alias email address
        /// </summary>
        /// <param name="aliasAddress">Alias e-mail address to search for</param>
        /// <returns>Returns a collection list of e-mail addresses for a specified e-mail mailing list</returns>
        public Collection<string> GetMailingList(string aliasAddress)
        {
            Collection<string> resultValue = new Collection<string>();

            MailAddress address = new MailAddress(aliasAddress);

            Domain localDomain = this.FindDomain(address.Host);

            if (localDomain != null)
            {
                // no user accounts matched this so check aliases
                IEnumerable<Alias> aliases = from alias in localDomain.Aliases
                                             where alias.AliasName == address.User.ToLower()
                                             select alias;

                if (aliases != null ? aliases.Count<Alias>() > 0 : false)
                {
                    // we found an alias for this address, get account name...
                    Alias aliasFound = aliases.ElementAt<Alias>(0);
                    if (aliasFound != null)
                    {
                        resultValue = aliasFound.MailingList;
                    }
                }
            }

            return resultValue;
        }
        #endregion
    }
}
